﻿using System;
using System.Collections.Generic;
using System.Numerics;

namespace NodeBasedSkillEditor
{
    public class BasePort
    {
        public uint PortLocalId;

        #region Editor Only

        public virtual Type GetDataType() { return typeof(object); }

        #endregion
    }

    /// <summary>
    /// PortGroup的PortId仅对编辑器有意义，运行使用中是没有用处的
    /// 在编辑器中，PortGroup会提供一个默认的ExpandPort，PortId也会赋予ExpandPort
    /// 当用户在编辑时连接ExpandPort，会新建一个Port并完成连接，ExpandPort依然保持未连接状态
    /// </summary>
    public class PortGroup : BasePort
    {
        public List<BasePort> Ports = new List<BasePort>(4);

        public BasePort ExpandPortData;

        public override Type GetDataType() { return ExpandPortData?.GetDataType(); }

        public PortGroup(Type portType)
        {
            ExpandPortData = Activator.CreateInstance(portType) as BasePort;
        }

        // 仅限反序列化使用, 默认PortData类型为ValuePort
        public PortGroup()
        {
            ExpandPortData = new ValuePort();
        }
    }

    public class FlowPort : BasePort
    {
        public override Type GetDataType() { return typeof(FlowPort); }
    }

    /// <summary>
    /// 由此派生的Port类都应该具有可以在编辑器里编辑的值，并定义为Value
    /// 为了避免装箱拆箱的开销和GC，所有的值类型都被封装到Class中，统一分配在堆上使用
    /// Unity无法使用Span<T>，为了保证一套数据类代码两边兼容，故只能采用此方法
    /// </summary>
    public class ValuePort : BasePort
    {
        /// <summary>注意，此接口会导致装箱和拆箱，仅限编辑器下调用，不应在游戏运行中使用</summary>
        public virtual object GetValue() { return null; }
        /// <summary>注意，此接口会导致装箱和拆箱，仅限编辑器下调用，不应在游戏运行中使用</summary>
        public virtual bool SetValue(object value) { return false; }
    }

    public abstract class EnumPort : ValuePort
    {
        //public abstract Type EnumType { get; }
        [Swifter.RW.RWField(Access = Swifter.RW.RWFieldAccess.Ignore)]
        public abstract Enum Value { get; set; }
    }

    public class BooleanPort : ValuePort
    {
        public override Type GetDataType() {  return typeof(bool); }

        public bool Value;

        public BooleanPort() { }

        public BooleanPort(bool value)
        {
            Value = value;
        }


        public override object GetValue() { return Value; }
        public override bool SetValue(object value)
        {
            try
            {
                Value = (bool)value;
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }

    public class IntegerPort : ValuePort
    {
        public override Type GetDataType() {  return typeof(int); }

        public int Value;

        public IntegerPort() { }

        public IntegerPort(int value)
        {
            Value = value;
        }

        public override object GetValue() { return Value; }
        public override bool SetValue(object value)
        {
            try
            {
                Value = (int)value;
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }

    public class FloatPort : ValuePort
    {
        public override Type GetDataType() { return typeof(float); }

        public float Value;

        public FloatPort() { }

        public FloatPort(float value)
        {
            Value = value;
        }

        public override object GetValue() { return Value; }
        public override bool SetValue(object value)
        {
            try
            {
                Value = (float)value;
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }

    public class Vector2Port : ValuePort
    {
        public override Type GetDataType() {  return typeof(Vector2); }

        public Vector2 Value;

        public Vector2Port() { }

        public Vector2Port(Vector2 value)
        {
            Value = value;
        }

        public override object GetValue() { return Value; }
        public override bool SetValue(object value)
        {
            try
            {
                Value = (Vector2)value;
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }

    public class Vector3Port : ValuePort
    {
        public override Type GetDataType() { return typeof(Vector3); }

        public Vector3 Value;

        public Vector3Port() { }

        public Vector3Port(Vector3 value)
        {
            Value = value;
        }

        public override object GetValue() { return Value; }
        public override bool SetValue(object value)
        {
            try
            {
                Value = (Vector3)value;
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }

    public class StringPort : ValuePort
    {
        public override Type GetDataType() {  return typeof(string); }

        public string Value;

        public StringPort() { }

        public StringPort(string value)
        {
            Value = value;
        }

        public override object GetValue() { return Value; }
        public override bool SetValue(object value)
        {
            try
            {
                Value = value.ToString();
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }

    public class EnumPort<T> : EnumPort where T : Enum
    {
        public override Type GetDataType() { return typeof(T); }

        public T EnumValue = default(T);

        [Swifter.RW.RWField(Access = Swifter.RW.RWFieldAccess.Ignore)]
        public override Enum Value {
            get { return EnumValue; }
            set { EnumValue = (T)value; }
        }

        public EnumPort() { }

        public EnumPort(T enumValue)
        {
            EnumValue = enumValue;
        }

        public override object GetValue() { return Value; }
        public override bool SetValue(object value)
        {
            try
            {
                EnumValue = (T)value;
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }

}
